P3327 [SDOI2015]约数个数和

首先可以得出 d(ij)=xiyj(gcd(x,y)=1)d(ij)=\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=1)

证明

首先令 i=p1α1p2α2...pkαk,j=p1β1p2β2...pkβki=p_1^{\alpha_1}p_2^{\alpha_2}...p_k^{\alpha_k},j=p_1^{\beta_1}p_2^{\beta_2}...p_k^{\beta_k}

那么 ij=p1α1+β1p2α2+β2...pkαk+βkij=p_1^{\alpha_1+\beta_1}p_2^{\alpha_2+\beta_2}...p_k^{\alpha_k+\beta_k}

可以得出约数个数为 (α1+β2+1)(α2+β2+1)...(αk+βk+1)(\alpha_1+\beta_2+1)(\alpha_2+\beta_2+1)...(\alpha_k+\beta_k+1)

xi,yj,gcd(x,y)=1x|i,y|j,gcd(x,y)=1

可知对于每一个 pip_i,

x,yx,y 可以选 (pi0,pi0),(pi1,pi0)...(piαi,pi0),(pi0,pi1)...(pi0,piβi)(p_i^0,p_i^0),(p_i^1,p_i^0)...(p_i^{\alpha^i},p_i^0),(p_i^0,p_i^1)...(p_i^0,p_i^{\beta^i})

一共是 αi+βi+1\alpha^i+\beta^i+1 种选择

那么加起来就等于约数个数了

证毕

接下来才是重头戏

i=1nj=1md(ij)=i=1nj=1mxiyj(gcd(x,y)=1)\sum\limits_{i=1}^n\sum\limits_{j=1}^md(ij)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=1)

Fk=i=1nj=1mxiyj(kgcd(x,y)),fk=i=1nj=1mxiyj(gcd(x,y)=k)F_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(k|gcd(x,y)),f_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(gcd(x,y)=k)

Fk=kdfdF_k=\sum\limits_{k|d}f_d

由莫比乌斯反演可以得出 fk=ndμ(dn)Fdf_k=\sum\limits_{n|d}\mu(\frac{d}{n})F_d

但是到这依然不好求,考虑优化一下 FkF_k

Fk=i=1nj=1mxiyj(kgcd(x,y))F_k=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}(k|gcd(x,y))

交换一下循环顺序

Fk=x=1ny=1m?F_k=\sum\limits_{x=1}^n\sum\limits_{y=1}^m?

可以得出外面两层循环的范围,那么里面两层呢?可以看出最里面的值与 i,ji,j 无关,所以只需要考虑 (n,m)(n,m) 有多少个 (i,j)(i,j) 满足里面的条件,得出

Fk=x=1ny=1mnxmy(kgcd(x,y))F_k=\sum\limits_{x=1}^n\sum\limits_{y=1}^m\lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{y}\rfloor (k|gcd(x,y))

x=xk,y=yk,n=nk,m=mkx`=\frac{x}{k},y`=\frac{y}{k},n`=\frac{n}{k},m`=\frac{m}{k},得

Fk=x=1ny=1mnxmyF_k=\sum\limits_{x`=1}^{n`}\sum\limits_{y`=1}^{m`}\lfloor\frac{n`}{x`}\rfloor\lfloor\frac{m`}{y`}\rfloor

尝试将它展开,可以得到类似于 a1b1+a1b2+...+a1bn+a2b1+...+a2bn+...a_1 b_1+a_1 b_2+...+a_1 b_n+a_2 b_1+...+a_2 b_n+... 的形式,等于 (a1+a2+...+an)(b1+b2+...+bn)(a_1+a_2+...+a_n)(b_1+b_2+...+b_n)

那么 Fk=(x=1nnx)(y=1mmy)F_k=(\sum\limits_{x`=1}^{n`}\lfloor\frac{n`}{x`}\rfloor)(\sum\limits_{y`=1}^{m`}\lfloor\frac{m`}{y`}\rfloor)

不妨令 h(x)=i=1xxih(x)=\sum\limits_{i=1}^x\lfloor\frac{x}{i}\rfloor

Fk=h(nk)h(mk)F_k=h(\frac{n}{k})h(\frac{m}{k})

再代回上面的式子

fk=kdμ(dk)h(nd)h(md)f_k=\sum\limits_{k|d}\mu(\frac{d}{k})h(\frac{n}{d})h(\frac{m}{d})

到这就很明显可以用整除分块预处理出来所有的 h(x)h(x) 和求答案了

代码

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 5e4 + 5;
typedef long long ll;

int prime[N], mu[N], sum[N], h[N], tot;
bool st[N];

int g(int k, int x)
{
return k / (k / x);
}

void init()
{
mu[1] = 1;
for (int i = 2; i < N; i++)
{
if (!st[i])
prime[++tot] = i, mu[i] = -1;
for (int j = 1; prime[j] * i < N; j++)
{
st[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i < N; i++)
sum[i] = sum[i - 1] + mu[i];
for (int i = 1; i < N; i++)
{
for (int l = 1, r; l <= i; l = r + 1)
{
r = min(i, g(i, l));
h[i] += (r - l + 1) * (i / l);
}
}
}

int main()
{
init();
int T;
scanf("%d", &T);
while (T--)
{
int n, m;
scanf("%d%d", &n, &m);
int k = min(n, m);
ll ans = 0;
for (int l = 1, r; l <= k; l = r + 1)
{
r = min(k, min(g(n, l), g(m, l)));
ans += (ll)(sum[r] - sum[l - 1]) * h[n / l] * h[m / l];
}
printf("%lld\n", ans);
}
return 0;
}